﻿using System;
using System.Collections.Generic;
using UnityEngine;

public class CollisionManager : MonoBehaviour
{
    private static CollisionEventArgs eventArgs;

    public delegate void CollisionEventHandler(object sender, CollisionEventArgs e);
    public static event CollisionEventHandler OnCollison;
    private CollisionSide lastSide;
    private void Start()
    {
        eventArgs = new CollisionEventArgs();
        lastSide = CollisionSide.None;
    }

    private void OnCollisionEnter(Collision coll)
    {
        eventArgs.CollisionType = CollisionType.Enter;
        eventArgs.CollisionSide = CheckPlayerCollision(coll);
        eventArgs.OtherObject = coll.gameObject;
        eventArgs.ThisObject = gameObject;

        if (OnCollison != null)
            OnCollison(this, eventArgs);
        lastSide = eventArgs.CollisionSide;
    }

    private void OnCollisionStay(Collision coll)
    {
        eventArgs.CollisionType = CollisionType.Stay;
        eventArgs.CollisionSide = CheckPlayerCollision(coll);
        eventArgs.OtherObject = coll.gameObject;
        eventArgs.ThisObject = gameObject;

        if (OnCollison != null)
        {
            OnCollison(this, eventArgs);

            if (eventArgs.CollisionSide != lastSide)
            {
                CollisionEventArgs exitArgs = new CollisionEventArgs
                    {
                        CollisionType = CollisionType.Exit,
                        CollisionSide = lastSide,
                        OtherObject = coll.gameObject,
                        ThisObject = gameObject
                    };
                OnCollison(this, exitArgs);
            }
        }
        lastSide = eventArgs.CollisionSide;
    }

    private void OnCollisionExit(Collision coll)
    {
        eventArgs.CollisionType = CollisionType.Exit;
        eventArgs.CollisionSide = CheckPlayerCollision(coll);
        eventArgs.OtherObject = coll.gameObject;
        eventArgs.ThisObject = gameObject;

        if (OnCollison != null)
            OnCollison(this, eventArgs);
        lastSide = eventArgs.CollisionSide;
    }

    private void OnTriggerEnter(Component other)
    {
        eventArgs.CollisionType = CollisionType.Enter;
        eventArgs.OtherObject = other.transform.gameObject;
        eventArgs.ThisObject = gameObject;
        eventArgs.Trigger = true;

        if (OnCollison != null)
            OnCollison(this, eventArgs);
        lastSide = eventArgs.CollisionSide;
    }

    private static CollisionSide CheckPlayerCollision(Collision collision)
    {
        if (collision != null)
        {
            List<ContactPoint> left = new List<ContactPoint>();
            List<ContactPoint> right = new List<ContactPoint>();
            List<ContactPoint> up = new List<ContactPoint>();
            List<ContactPoint> down = new List<ContactPoint>();

            foreach (ContactPoint cp in collision.contacts)
            {
                Debug.DrawRay(cp.point, cp.normal, Color.red);

                Vector3 temp = new Vector3(Mathf.RoundToInt(cp.normal.x), Mathf.RoundToInt(cp.normal.y),
                                           Mathf.RoundToInt(cp.normal.z));

                if (temp == -Vector3.up)
                {
                    up.Add(cp);
                }
                else if (temp == Vector3.up)
                {
                    down.Add(cp);
                }
                else if (temp == -Vector3.left)
                {
                    left.Add(cp);
                }
                else if (temp == Vector3.left)
                {
                    right.Add(cp);
                }
            }

            List<ContactPoint> list1;
            List<ContactPoint> list2;

            CollisionSide cs1, cs2;

            if (left.Count > right.Count)
            {
                list1 = left;
                cs1 = CollisionSide.Left;
            }
            else
            {
                list1 = right;
                cs1 = CollisionSide.Right;
            }
            if (up.Count > down.Count)
            {
                list2 = up;
                cs2 = CollisionSide.Up;
            }
            else
            {
                list2 = down;
                cs2 = CollisionSide.Down;
            }

            return list1.Count > list2.Count ? cs1 : cs2;
        }

        return CollisionSide.None;
    }
}

public class CollisionEventArgs : EventArgs
{
    public CollisionSide CollisionSide;
    public CollisionType CollisionType;
    public GameObject OtherObject;
    public GameObject ThisObject;
    public bool Trigger;

    public CollisionEventArgs()
    {
        this.CollisionSide = CollisionSide.None;
        this.CollisionType = CollisionType.None;
        Trigger = false;
    }
}